简介 FlycoTabLayout ,是一个比Google原生TabLayout 功能更强大的TabLayout库。目前有3种TabLayout:
SlidingTabLayout
CommonTabLayout
SegmentTabLayout
具体介绍和使用方法参考开源库的Wiki
官方示例:
源码分析
共有属性名称
格式
描述
tl_indicator_color
color
设置显示器颜色
tl_indicator_height
dimension
设置显示器高度
tl_indicator_margin_left
dimension
设置显示器margin,当indicator_width大于0,无效
tl_indicator_margin_top
dimension
设置显示器margin,当indicator_width大于0,无效
tl_indicator_margin_right
dimension
设置显示器margin,当indicator_width大于0,无效
tl_indicator_margin_bottom
dimension
设置显示器margin,当indicator_width大于0,无效
tl_indicator_corner_radius
dimension
设置显示器圆角弧度
tl_divider_color
color
设置分割线颜色
tl_divider_width
dimension
设置分割线宽度
tl_divider_padding
dimension
设置分割线的paddingTop和paddingBottom
tl_tab_padding
dimension
设置tab的paddingLeft和paddingRight
tl_tab_space_equal
boolean
设置tab大小等分
tl_tab_width
dimension
设置tab固定大小
tl_textsize
dimension
设置字体大小
tl_textSelectColor
color
设置字体选中颜色
tl_textUnselectColor
color
设置字体未选中颜色
tl_textBold
boolean
设置字体加粗
tl_textAllCaps
boolean
设置字体全大写
1. SlidingTabLayout 1.1 特有属性
特有属性
格式
描述
tl_indicator_width
dimension
设置显示器固定宽度
tl_indicator_gravity
enum
设置显示器上方(TOP)还是下方(BOTTOM),只对常规显示器有用
tl_indicator_style
enum
设置显示器为常规(NORMAL)或三角形(TRIANGLE)或背景色块(BLOCK)
tl_indicator_width_equal_title
boolean
设置显示器与标题一样长(only for SlidingTabLayout)
tl_underline_color
color
设置下划线颜色
tl_underline_height
dimension
设置下划线高度
tl_underline_gravity
enum
设置下划线上方(TOP)还是下方(BOTTOM)
1.2 类结构 1.2.1 构造方法 第一个调用第二个,第二个调用第三个,第三个获取自定义属性值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public SlidingTabLayout (Context context, AttributeSet attrs, int defStyleAttr) { super (context, attrs, defStyleAttr); setFillViewport(true ); setWillNotDraw(false ); setClipChildren(false ); setClipToPadding(false ); this .mContext = context; mTabsContainer = new LinearLayout(context); addView(mTabsContainer); obtainAttributes(context, attrs); String height = attrs.getAttributeValue("http://schemas.android.com/apk/res/android" , "layout_height" ); if (height.equals(ViewGroup.LayoutParams.MATCH_PARENT + "" )) { } else if (height.equals(ViewGroup.LayoutParams.WRAP_CONTENT + "" )) { } else { int [] systemAttrs = {android.R.attr.layout_height}; TypedArray a = context.obtainStyledAttributes(attrs, systemAttrs); mHeight = a.getDimensionPixelSize(0 , ViewGroup.LayoutParams.WRAP_CONTENT); a.recycle(); } }
方法
描述
setViewPager(ViewPager vp)
设置ViewPager内容
public void setViewPager(ViewPager vp, String[] titles)
设置ViewPager内容和标签页的标题
1 2 3 4 5 6 7 8 9 10 11 12 13 public void setViewPager (ViewPager vp) { if (vp == null || vp.getAdapter() == null ) { throw new IllegalStateException("ViewPager or ViewPager adapter can not be NULL !" ); } this .mViewPager = vp; this .mViewPager.removeOnPageChangeListener(this ); this .mViewPager.addOnPageChangeListener(this ); notifyDataSetChanged(); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public void notifyDataSetChanged () { mTabsContainer.removeAllViews(); this .mTabCount = mTitles == null ? mViewPager.getAdapter().getCount() : mTitles.size(); View tabView; for (int i = 0 ; i < mTabCount; i++) { tabView = View.inflate(mContext, R.layout.layout_tab, null ); CharSequence pageTitle = mTitles == null ? mViewPager.getAdapter().getPageTitle(i) : mTitles.get(i); addTab(i, pageTitle.toString(), tabView); } updateTabStyles(); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 private void addTab (final int position, String title, View tabView) { TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title); if (tv_tab_title != null ) { if (title != null ) tv_tab_title.setText(title); } tabView.setOnClickListener(new OnClickListener() { @Override public void onClick (View v) { int position = mTabsContainer.indexOfChild(v); if (position != -1 ) { if (mViewPager.getCurrentItem() != position) { if (mSnapOnTabClick) { mViewPager.setCurrentItem(position, false ); } else { mViewPager.setCurrentItem(position); } if (mListener != null ) { mListener.onTabSelect(position); } } else { if (mListener != null ) { mListener.onTabReselect(position); } } } } }); LinearLayout.LayoutParams lp_tab = mTabSpaceEqual ? new LinearLayout.LayoutParams(0 , LayoutParams.MATCH_PARENT, 1.0f ) : new LinearLayout.LayoutParams( LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); if (mTabWidth > 0 ) { lp_tab = new LinearLayout.LayoutParams((int ) mTabWidth, LayoutParams.MATCH_PARENT); } mTabsContainer.addView(tabView, position, lp_tab); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 private void updateTabStyles () { for (int i = 0 ; i < mTabCount; i++) { View v = mTabsContainer.getChildAt(i); TextView tv_tab_title = (TextView) v.findViewById(R.id.tv_tab_title); if (tv_tab_title != null ) { tv_tab_title.setTextColor(i == mCurrentTab ? mTextSelectColor : mTextUnselectColor); tv_tab_title.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextsize); tv_tab_title.setPadding((int ) mTabPadding, 0 , (int ) mTabPadding, 0 ); if (mTextAllCaps) { tv_tab_title.setText(tv_tab_title.getText().toString().toUpperCase()); } if (mTextBold == TEXT_BOLD_BOTH) { tv_tab_title.getPaint().setFakeBoldText(true ); } else if (mTextBold == TEXT_BOLD_NONE) { tv_tab_title.getPaint().setFakeBoldText(false ); } } } }
方法
描述
setViewPager(ViewPager vp, String[] titles, FragmentActivity fa, ArrayList< Fragment > fragments)
设置ViewPager,标题内容,FragmentActivity和用于显示的Fragment,用来设置ViewPager的Adapter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public void setViewPager (ViewPager vp, String[] titles, FragmentActivity fa, ArrayList<Fragment> fragments) { if (vp == null ) { throw new IllegalStateException("ViewPager can not be NULL !" ); } if (titles == null || titles.length == 0 ) { throw new IllegalStateException("Titles can not be EMPTY !" ); } this .mViewPager = vp; this .mViewPager.setAdapter(new InnerPagerAdapter(fa.getSupportFragmentManager(), fragments, titles)); this .mViewPager.removeOnPageChangeListener(this ); this .mViewPager.addOnPageChangeListener(this ); notifyDataSetChanged(); }
看下这个内部的InnerPagerAdapter,静态Fragment,不销毁重建,只更新数据内容。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 class InnerPagerAdapter extends FragmentPagerAdapter { private ArrayList<Fragment> fragments = new ArrayList<>(); private String[] titles; public InnerPagerAdapter (FragmentManager fm, ArrayList<Fragment> fragments, String[] titles) { super (fm); this .fragments = fragments; this .titles = titles; } @Override public int getCount () { return fragments.size(); } @Override public CharSequence getPageTitle (int position) { return titles[position]; } @Override public Fragment getItem (int position) { return fragments.get(position); } @Override public void destroyItem (ViewGroup container, int position, Object object) { } @Override public int getItemPosition (Object object) { return PagerAdapter.POSITION_NONE; } }
方法
描述
onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
页面滚动,position为当前位置,positionOffset范围[0,1),从当前到下一页,positionOffsetPixels从当前位置滚动的offset,单位px
onPageSelected(int position)
选中位置
onPageScrollStateChanged(int state)
滚动状态改变
SCROLL_STATE_IDLE(pager处于空闲状态) SCROLL_STATE_DRAGGING( pager处于正在拖拽中) SCROLL_STATE_SETTLING(pager正在自动沉降,相当于松手后,pager恢复到一个完整pager的过程)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 @Override public void onPageScrolled (int position, float positionOffset, int positionOffsetPixels) { this .mCurrentTab = position; this .mCurrentPositionOffset = positionOffset; scrollToCurrentTab(); invalidate(); } @Override public void onPageSelected (int position) { updateTabSelection(position); } @Override public void onPageScrollStateChanged (int state) {}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 private void scrollToCurrentTab () { if (mTabCount <= 0 ) { return ; } int offset = (int ) (mCurrentPositionOffset * mTabsContainer.getChildAt(mCurrentTab).getWidth()); int newScrollX = mTabsContainer.getChildAt(mCurrentTab).getLeft() + offset; if (mCurrentTab > 0 || offset > 0 ) { newScrollX -= getWidth() / 2 - getPaddingLeft(); calcIndicatorRect(); newScrollX += ((mTabRect.right - mTabRect.left) / 2 ); } if (newScrollX != mLastScrollX) { mLastScrollX = newScrollX; scrollTo(newScrollX, 0 ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 private void updateTabSelection (int position) { for (int i = 0 ; i < mTabCount; ++i) { View tabView = mTabsContainer.getChildAt(i); final boolean isSelect = i == position; TextView tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title); if (tab_title != null ) { tab_title.setTextColor(isSelect ? mTextSelectColor : mTextUnselectColor); if (mTextBold == TEXT_BOLD_WHEN_SELECT) { tab_title.getPaint().setFakeBoldText(isSelect); } } } }
1.2.3 Tab相关
方法
描述
addNewTab(String title)
提供给外部使用的新增tab的方法
1 2 3 4 5 6 7 8 9 10 11 12 public void addNewTab (String title) { View tabView = View.inflate(mContext, R.layout.layout_tab, null ); if (mTitles != null ) { mTitles.add(title); } CharSequence pageTitle = mTitles == null ? mViewPager.getAdapter().getPageTitle(mTabCount) : mTitles.get(mTabCount); addTab(mTabCount, pageTitle.toString(), tabView); this .mTabCount = mTitles == null ? mViewPager.getAdapter().getCount() : mTitles.size(); updateTabStyles(); }
方法
描述
setCurrentTab(int currentTab)
跳转到指定tab,是否平滑的滚动过去由系统控制
setCurrentTab(int currentTab, boolean smoothScroll)
跳转到制指定tab, smoothScroll控制是否平滑的滚动过去
1 2 3 4 5 6 7 8 9 10 public void setCurrentTab (int currentTab) { this .mCurrentTab = currentTab; mViewPager.setCurrentItem(currentTab); } public void setCurrentTab (int currentTab, boolean smoothScroll) { this .mCurrentTab = currentTab; mViewPager.setCurrentItem(currentTab, smoothScroll); }
1.2.4 Getter和Setter 不做赘述
1.2.5 MsgView相关(未读信息)
方法
描述
showMsg(int position, int num)
显示未读消息,position为tab位置,num小于等于0显示红点,num大于0显示数字
showDot(int position)
显示未读红点, position为tab位置
hideMsg(int position)
隐藏未读消息, position为tab位置
setMsgMargin(int position, float leftPadding, float bottomPadding)
设置未读消息偏移,原点为文字的右上角.当控件高度固定,消息提示位置易控制,显示效果佳
getMsgView(int position)
当前类只提供了少许设置未读消息属性的方法,可以通过该方法获取MsgView对象从而各种设置
2. CommonTabLayout 2.1 特有属性
特有属性
格式
描述
tl_indicator_width
dimension
设置显示器固定宽度
tl_indicator_gravity
enum
设置显示器上方(TOP)还是下方(BOTTOM),只对常规显示器有用
tl_indicator_style
enum
设置显示器为常规(NORMAL)或三角形(TRIANGLE)或背景色块(BLOCK)
tl_indicator_anim_enable
boolean
设置显示器支持动画(only for CommonTabLayout)
tl_indicator_anim_duration
integer
设置显示器动画时间(only for CommonTabLayout)
tl_indicator_bounce_enable
boolean
设置显示器支持动画回弹效果(only for CommonTabLayout)
tl_underline_color
color
设置下划线颜色
tl_underline_height
dimension
设置下划线高度
tl_underline_gravity
enum
设置下划线上方(TOP)还是下方(BOTTOM)
tl_iconWidth
dimension
设置icon宽度(仅支持CommonTabLayout)
tl_iconHeight
dimension
设置icon高度(仅支持CommonTabLayout)
tl_iconVisible
boolean
设置icon是否可见(仅支持CommonTabLayout)
tl_iconGravity
enum
设置icon显示位置,对应Gravity中常量值,左上右下(仅支持CommonTabLayout),LEFT,RIGHT,TOP,BOTTOM
tl_iconMargin
dimension
设置icon与文字间距(仅支持CommonTabLayout)
2.2 区别于SlidingTabLayout
不依赖于ViewPager,可以与其他组件搭配
支持自定义Tab样式,主要体现在常用的图标+文字的形式。
SlidingTabLayout继承HorizontalScrollView而CommonTabLayout继承FrameLayout
2.3 类结构 2.3.1 构造方法 与SlidingTabLayout实现类似,获取的属性值不太一样而已。多出一个动画的内容,点击某一个Tab后,indicator的移动动画效果
1 2 mValueAnimator = ValueAnimator.ofObject(new PointEvaluator(), mLastP, mCurrentP); mValueAnimator.addUpdateListener(this );
2.3.2 动画相关 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class IndicatorPoint { public float left; public float right; } private IndicatorPoint mCurrentP = new IndicatorPoint();private IndicatorPoint mLastP = new IndicatorPoint();class PointEvaluator implements TypeEvaluator <IndicatorPoint > { @Override public IndicatorPoint evaluate (float fraction, IndicatorPoint startValue, IndicatorPoint endValue) { float left = startValue.left + fraction * (endValue.left - startValue.left); float right = startValue.right + fraction * (endValue.right - startValue.right); IndicatorPoint point = new IndicatorPoint(); point.left = left; point.right = right; return point; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Override public void onAnimationUpdate (ValueAnimator animation) { View currentTabView = mTabsContainer.getChildAt(this .mCurrentTab); IndicatorPoint p = (IndicatorPoint) animation.getAnimatedValue(); mIndicatorRect.left = (int ) p.left; mIndicatorRect.right = (int ) p.right; if (mIndicatorWidth < 0 ) { } else { float indicatorLeft = p.left + (currentTabView.getWidth() - mIndicatorWidth) / 2 ; mIndicatorRect.left = (int ) indicatorLeft; mIndicatorRect.right = (int ) (mIndicatorRect.left + mIndicatorWidth); } invalidate(); }
2.3.3 Tab相关
方法
描述
setTabData(ArrayList< CustomTabEntity> tabEntitys)
设置tab entity
setTabData(ArrayList< CustomTabEntity> tabEntitys, FragmentActivity fa, int containerViewId, ArrayList< Fragment> fragments)
关联数据支持同时切换fragments
notifyDataSetChanged()
更新数据
setCurrentTab(int currentTab)
设置当前tab
1 2 3 4 5 6 7 8 9 10 11 public void setTabData (ArrayList<CustomTabEntity> tabEntitys) { if (tabEntitys == null || tabEntitys.size() == 0 ) { throw new IllegalStateException("TabEntitys can not be NULL or EMPTY !" ); } this .mTabEntitys.clear(); this .mTabEntitys.addAll(tabEntitys); notifyDataSetChanged(); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public void notifyDataSetChanged () { mTabsContainer.removeAllViews(); this .mTabCount = mTabEntitys.size(); View tabView; for (int i = 0 ; i < mTabCount; i++) { if (mIconGravity == Gravity.LEFT) { tabView = View.inflate(mContext, R.layout.layout_tab_left, null ); } else if (mIconGravity == Gravity.RIGHT) { tabView = View.inflate(mContext, R.layout.layout_tab_right, null ); } else if (mIconGravity == Gravity.BOTTOM) { tabView = View.inflate(mContext, R.layout.layout_tab_bottom, null ); } else { tabView = View.inflate(mContext, R.layout.layout_tab_top, null ); } tabView.setTag(i); addTab(i, tabView); } updateTabStyles(); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 private void addTab (final int position, View tabView) { TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title); tv_tab_title.setText(mTabEntitys.get(position).getTabTitle()); ImageView iv_tab_icon = (ImageView) tabView.findViewById(R.id.iv_tab_icon); iv_tab_icon.setImageResource(mTabEntitys.get(position).getTabUnselectedIcon()); tabView.setOnClickListener(new OnClickListener() { @Override public void onClick (View v) { int position = (Integer) v.getTag(); if (mCurrentTab != position) { setCurrentTab(position); if (mListener != null ) { mListener.onTabSelect(position); } } else { if (mListener != null ) { mListener.onTabReselect(position); } } } }); LinearLayout.LayoutParams lp_tab = mTabSpaceEqual ? new LinearLayout.LayoutParams(0 , LayoutParams.MATCH_PARENT, 1.0f ) : new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); if (mTabWidth > 0 ) { lp_tab = new LinearLayout.LayoutParams((int ) mTabWidth, LayoutParams.MATCH_PARENT); } mTabsContainer.addView(tabView, position, lp_tab); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 private void updateTabStyles () { for (int i = 0 ; i < mTabCount; i++) { View tabView = mTabsContainer.getChildAt(i); tabView.setPadding((int ) mTabPadding, 0 , (int ) mTabPadding, 0 ); TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title); tv_tab_title.setTextColor(i == mCurrentTab ? mTextSelectColor : mTextUnselectColor); tv_tab_title.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextsize); if (mTextAllCaps) { tv_tab_title.setText(tv_tab_title.getText().toString().toUpperCase()); } if (mTextBold == TEXT_BOLD_BOTH) { tv_tab_title.getPaint().setFakeBoldText(true ); } else if (mTextBold == TEXT_BOLD_NONE) { tv_tab_title.getPaint().setFakeBoldText(false ); } ImageView iv_tab_icon = (ImageView) tabView.findViewById(R.id.iv_tab_icon); if (mIconVisible) { iv_tab_icon.setVisibility(View.VISIBLE); CustomTabEntity tabEntity = mTabEntitys.get(i); iv_tab_icon.setImageResource(i == mCurrentTab ? tabEntity.getTabSelectedIcon() : tabEntity.getTabUnselectedIcon()); LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( mIconWidth <= 0 ? LinearLayout.LayoutParams.WRAP_CONTENT : (int ) mIconWidth, mIconHeight <= 0 ? LinearLayout.LayoutParams.WRAP_CONTENT : (int ) mIconHeight); if (mIconGravity == Gravity.LEFT) { lp.rightMargin = (int ) mIconMargin; } else if (mIconGravity == Gravity.RIGHT) { lp.leftMargin = (int ) mIconMargin; } else if (mIconGravity == Gravity.BOTTOM) { lp.topMargin = (int ) mIconMargin; } else { lp.bottomMargin = (int ) mIconMargin; } iv_tab_icon.setLayoutParams(lp); } else { iv_tab_icon.setVisibility(View.GONE); } } }
另外一个setTabData
1 2 3 4 5 6 public void setTabData (ArrayList<CustomTabEntity> tabEntitys, FragmentActivity fa, int containerViewId, ArrayList<Fragment> fragments) { mFragmentChangeManager = new FragmentChangeManager(fa.getSupportFragmentManager(), containerViewId, fragments); setTabData(tabEntitys); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public void setCurrentTab (int currentTab) { mLastTab = this .mCurrentTab; this .mCurrentTab = currentTab; updateTabSelection(currentTab); if (mFragmentChangeManager != null ) { mFragmentChangeManager.setFragments(currentTab); } if (mIndicatorAnimEnable) { calcOffset(); } else { invalidate(); } }
2.3.4 FragmentChangeManager
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 public class FragmentChangeManager { private FragmentManager mFragmentManager; private int mContainerViewId; private ArrayList<Fragment> mFragments; private int mCurrentTab; public FragmentChangeManager (FragmentManager fm, int containerViewId, ArrayList<Fragment> fragments) { this .mFragmentManager = fm; this .mContainerViewId = containerViewId; this .mFragments = fragments; initFragments(); } private void initFragments () { for (Fragment fragment : mFragments) { mFragmentManager.beginTransaction().add(mContainerViewId, fragment).hide(fragment).commit(); } setFragments(0 ); } public void setFragments (int index) { for (int i = 0 ; i < mFragments.size(); i++) { FragmentTransaction ft = mFragmentManager.beginTransaction(); Fragment fragment = mFragments.get(i); if (i == index) { ft.show(fragment); } else { ft.hide(fragment); } ft.commit(); } mCurrentTab = index; } public int getCurrentTab () { return mCurrentTab; } public Fragment getCurrentFragment () { return mFragments.get(mCurrentTab); } }
2.3.5 Getter,Setter以及MsgView先关 Getter和Setter方法是属性值的获取和设置,MsgView相关方法和SlidingTabLayout比较相似。
3. SegmentTabLayout 3.1 特有属性
特有属性
格式
描述
tl_indicator_anim_enable
boolean
设置显示器支持动画
tl_indicator_anim_duration
integer
设置显示器动画时间
tl_indicator_bounce_enable
boolean
设置显示器支持动画回弹效果
tl_bar_color
color
设置整体颜色
tl_bar_stroke_color
color
设置边框颜色
tl_bar_stroke_width
dimension
设置边框粗细
3.2 区别于CommonTabLayout
不支持图标,但是可以看做是一个特殊的CommonTabLayout.
3.3 类结构 整体来说,内容基本上和CommonTabLayout,只是少了Icon的对应处理,多出的是Segment样式的处理。
4. MsgView 4.1 自定义属性
属性值
格式
描述
mv_backgroundColor
color
圆角矩形背景色
mv_cornerRadius
dimension
圆角弧度,单位dp
mv_strokeWidth
dimension
边框粗细,单位dp
mv_strokeColor
color
圆角边框颜色
mv_isRadiusHalfHeight
boolean
圆角弧度是高度一半
mv_isWidthHeightEqual
boolean
圆角矩形宽高相等,取较宽高中大值
4.2 类结构
项目使用 个人项目Gank.io Android 客户端 中使用效果,底部使用的CommonTabLayout,顶部使用的是SlidingTabLayout。整体而言,日常开发过程中,FlycoTabLayout还是很实用的。